<?php
namespace Helpers;

use OSS\OssClient;
use MongoDB\BSON\ObjectID;
use MongoDB\Client as MongoClient;
use Phalcon\Http\Request\File as PhalconFile;
use Admin\Models\sys\File as FileModel;

class File
{

    /**
     * 获取文件名
     *
     * @param mixed $file
     * @return string
     * @throws \Exception
     *
     * create by ck 20181214
     * modify by ck 20181218    支持多种入参
     */
    public static function getFileName(&$file) : string
    {
        switch (gettype($file)) {
            case 'object':
                if ($file instanceof PhalconFile) {
                    $name = $file->getName();
                    $file = $file->getTempName();
                } else {
                    throw new \Exception('暂不支持该方式');
                }
                break;
            case 'array':
                $name = Tool::getValue($file, 'name');
                $file = Tool::getValue($file, 'tmp_name');
                break;
            case 'string':
                $file = realpath($file);
                $name = basename($file);
                break;
            default:
                throw new \Exception('文件传入有误，无法上传');
        }

        if (!$name || !$file) {
            throw new \Exception('文件信息有误');
        }
        if (!file_exists($file)) {
            throw new \Exception('文件不存在：' . $file);
        }
        return $name;
    }

    /**
     * 获取文件后缀
     *
     * @param $fileName
     * @return array|mixed
     *
     * create by ck 20181214
     */
    public static function getFileSuffix(string $fileName) : string
    {
        $fileSuffix = explode('.', $fileName);
        $fileSuffix = count($fileSuffix) > 1 ? end($fileSuffix) : '';
        return $fileSuffix;
    }

    /**
     * 上传到阿里oss
     *
     * @param mixed $file
     * @param string $module
     * @param string $subModule
     * @param string $key
     * @return array
     * @throws \Exception
     *
     * create by ck 20181213
     */
    public static function uploadOss($file, string $module = '', string $subModule = '', $key = '') : array
    {
        $config = Main::getConfigByName('oss');
        if (!$config) {
            throw new \Exception('oss配置不存在');
        }
        $fileName = self::getFileName($file);
        $fileSuffix = self::getFileSuffix($fileName);
        $key = $key ?: $config['key'];
        $md5Str = md5_file($file);

        $ossFileName = basename($md5Str . '.' . $fileSuffix);
        $ossClient   = new OssClient($config['accessKeyId'], $config['accessKeySecret'], $config['endpoint']);
        $object      = Tool::buildPath($key, $module, $subModule, date('Ymd'), $ossFileName);
        $result      = $ossClient->uploadFile($config['bucket'], $object, $file);
        $url         = $result['oss-request-url'];


        //保存记录
        $fileModel         = new FileModel(['position' => 1, 'module' => $module, 'subModule' => $subModule]);
        $fileModel->url    = $url;
        $fileModel->name   = $fileName;
        $fileModel->suffix = $fileSuffix;
        $fileModel->md5    = $md5Str;
        $fileModel->size   = filesize($file);
        if (!$fileModel->save()) {
            throw new \Exception($fileModel->getError());
        }
        return [
            'id'   => $fileModel->id,
            'url'  => $fileModel->url,
            'name' => $fileModel->name,
            'size' => $fileModel->size,
            'md5'  => $fileModel->md5,
        ];
    }

    /**
     * 获取MongoGridFS
     *
     * @param $module
     * @param $subModule
     * @return \MongoDB\GridFS\Bucket
     * @throws \Exception
     *
     * create by ck 20181214
     * modify by ck 20181218
     * modify by ck 20190102    添加认证
     */
    private static function getGridFSBucket(string $module, string $subModule)
    {
        static $mongo;
        if (!$mongo) {
            $config = Main::getConfigByName('mongoFile');
            if (!$config || !Tool::getValue($config, 'url') || !Tool::getValue($config, 'database')) {
                throw new \Exception('mongo配置有误');
            }
            $mongo = (new MongoClient($config['url']))->selectDatabase($config['database']);
        }
        $bucketName = "{$module}.{$subModule}";
        return $mongo->selectGridFSBucket(['bucketName' => $bucketName]);
    }

    /**
     * 上传文件到mongodb
     *
     * @param mixed $file
     * @param $module
     * @param $subModule
     * @return array
     * @throws \Exception
     *
     * create by ck 20181217
     */
    public static function upload($file, string $module, string $subModule) : array
    {
        $fileName   = self::getFileName($file);
        $fileSuffix = self::getFileSuffix($fileName);
        $bucket     = self::getGridFSBucket($module, $subModule);
        $fileId     = $bucket->uploadFromStream($fileName, fopen($file, 'rb'));

        //构建url
        $url = Tool::buildUrl(Tool::buildPath('file', 'download', $module, $subModule, $fileId));
        if ($fileSuffix) {
            $url .= ".{$fileSuffix}";
        }

        //保存记录
        $mongoFile         = $bucket->findOne(['_id' => new ObjectID($fileId)]);
        $fileModel         = new FileModel(['position' => 2, 'module' => $module, 'subModule' => $subModule]);
        $fileModel->url    = $url;
        $fileModel->name   = $fileName;
        $fileModel->suffix = $fileSuffix;
        $fileModel->md5    = $mongoFile->md5;
        $fileModel->size   = $mongoFile->length;
        if (!$fileModel->save()) {
            throw new \Exception($fileModel->getError());
        }
        return [
            'id'   => $fileModel->id,
            'url'  => $fileModel->url,
            'name' => $fileModel->name,
            'size' => $fileModel->size,
            'md5'  => $fileModel->md5,
        ];
    }

    /**
     * 下载mongo文件
     *
     * @param $module
     * @param $subModule
     * @param $fileId
     * @return bool
     * @throws \Exception
     *
     * create by ck 20181218
     */
    public static function download($module, $subModule, $fileId)
    {
        $bucket   = self::getGridFSBucket($module, $subModule);
        $fileId   = new ObjectID($fileId);
        $fileInfo = $bucket->findOne(['_id' => $fileId]);
        if (!$fileInfo) {
            throw new \Exception('找不到文件');
        }

        //打开下载
        Header("Content-type: application/octet-stream");
        Header("Accept-Ranges: bytes");
        Header("Accept-Length: {$fileInfo->length}");
        Header("Content-Disposition: attachment; filename={$fileInfo->filename}");
        $bucket->downloadToStream($fileId, fopen('php://output', 'w+b'));
        return true;
    }
}
